use chrono::Local;
use sqlite_wasm_rs::sqlite3_stmt;
use crate::db::dao::base_dao::Adder;
use crate::db::db::{Db, DbParamType};
use crate::db::pojo::pojo::{ImMessageActionData, ImMessageSend};
use crate::db::util::{db_get_enum, db_get_int64, db_get_string, db_get_time};

const SELECT_COLUMNS: &str = "id, messageId, userId, status, fileStatus, actionStatus, createTime, updateTime";

pub fn message_send_inserts(db: Db, message_sends: &mut Vec<&mut ImMessageSend>) {
    if message_sends.is_empty() { return; }
    let sql = "insert into im_message_send(messageId, userId, status, fileStatus, actionStatus, createTime, updateTime) values(?, ?, ?, ?, ?, ?, ?)";

    let mut params_list = vec![];
    for message_send in message_sends.iter() {
        let mut params = vec![];
        params.push(DbParamType::Uint(message_send.message_id.unwrap()));
        params.push(DbParamType::Str(&*message_send.user_id));
        params.push(DbParamType::Byte(message_send.status.clone() as i8));
        params.push(DbParamType::Byte(message_send.file_status.clone() as i8));
        params.push(DbParamType::Byte(message_send.action_status.clone() as i8));
        params.push(DbParamType::DateTime2(&message_send.create_time));
        params.push(DbParamType::DateTime2(&message_send.update_time));

        params_list.push(params);
    }

    let ids = db.inserts2("message send insert", sql, params_list);
    assert_eq!(ids.len(), message_sends.len(), "批量插入数据没有都生成主键(message_send)");
    for (idx, value) in ids.iter().enumerate() {
        let message_send = message_sends.get_mut(idx).unwrap();
        message_send.id = Some(value.clone());
    }
}

pub fn message_send_updates(db: Db, message_sends: &mut Vec<ImMessageSend>) {
    if message_sends.is_empty() { return; }

    let sql = "update im_message_send set updateTime = ?, actionStatus = ? where id = ?";

    let mut params_list = vec![];
    for message_send in message_sends.iter() {
        let mut params = vec![];
        params.push(DbParamType::DateTime2(&message_send.update_time));
        params.push(DbParamType::Byte(message_send.action_status.clone() as i8));
        params.push(DbParamType::Uint(message_send.id.clone().unwrap()));
        
        params_list.push(params);
    }

    db.batch_exec("message send updates", sql.to_string(), params_list)
}

pub fn change_message_send_action_status(db: Db, message_action_data_list: Vec<ImMessageActionData>) {
    if message_action_data_list.is_empty() { return; }

    let sql = "update im_message_send set actionStatus = ?, updateTime = ? where messageId = ? and userId= ?";
    let mut params_list = vec![];
    for message_action_data in message_action_data_list.iter() {
        let mut params = vec![];
        params.push(DbParamType::Byte(message_action_data.action_status.clone() as i8));
        params.push(DbParamType::DateTime(Local::now()));
        params.push(DbParamType::Uint(message_action_data.message_id));
        params.push(DbParamType::Str(&message_action_data.user_id));
        params_list.push(params);
    }
    db.batch_exec("message send status", sql.to_string(), params_list);
}

pub fn message_send_is_syn_end(db: Db, message_id: u64) -> bool {
    let sql = c"select count(*) from im_message_send where messageId = ?";
    let mut params = vec![];
    params.push(DbParamType::Uint(message_id));
    let total1 = db.count("message send total", sql, params);

    let sql2 = c"select count(*) from im_message_send where actionStatus in ('2', '7') and messageId = ?";
    let mut params2 = vec![];
    params2.push(DbParamType::Uint(message_id));
    let total2 = db.count("message send total", sql2, params2);

    total1 == total2
}

pub fn message_send_query_by_user_id(db: Db, message_id: u64, user_id: String) -> Option<ImMessageSend> {
    let sql = format!("select {} from im_message_send where messageId = ? and userId = ?", SELECT_COLUMNS);
    let mut params = vec![];
    params.push(DbParamType::Uint(message_id));
    params.push(DbParamType::Str(&user_id));
    db.query_one("message send query", sql, params, Box::new(message_send_wrap))
}

pub fn message_send_query_by_message_id(db: Db, message_id: u64) -> Vec<ImMessageSend> {
    let sql = format!("select {} from im_message_send where messageId = ?", SELECT_COLUMNS);
    let mut params = vec![];
    params.push(DbParamType::Uint(message_id));
    db.query2("message send query2", sql.as_str(), params, Box::new(message_send_wrap))
}


fn message_send_wrap(stmt: *mut sqlite3_stmt) -> ImMessageSend {
    unsafe {
        let mut adder = Adder::new();

        let id = db_get_int64(stmt, adder.add());
        let message_id = db_get_int64(stmt, adder.add());
        let user_id = db_get_string(stmt, adder.add()).unwrap();
        let status = db_get_enum(stmt, adder.add());
        let file_status = db_get_enum(stmt, adder.add());
        let action_status = db_get_enum(stmt, adder.add());

        let create_time = db_get_time(stmt, adder.add());
        let update_time = db_get_time(stmt, adder.add());

        ImMessageSend {
            id: Some(id),
            message_id: Some(message_id),
            user_id,
            status,
            file_status,
            action_status,
            create_time,
            update_time,
        }
    }
}